﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using XmlStudio.DataLayer;
using XmlStudio.Models;
using XmlStudio.Interfaces;

namespace XmlStudio.Tests.XsdTests {
    [TestClass]
    public class XsdFactoryTest {
        private IXsdModel model;
        private const string XsPrefix = "xs";
        private const string XsNamespaceUri = "http://www.w3.org/2001/XMLSchema";

        [TestInitialize]
        public void MyTestInitialize() {
            this.model = ModelFactory.CreateXsdModel();
        }

        [TestMethod]
        public void XsdElementAll() {
            const string id = "1";
            const int maxOccurs = 1;
            const int minOccurs = 0;

            var all = XsdFactory.CreateElementAll(model, id, maxOccurs, minOccurs, null, null);
            Assert.IsNotNull(all);
            Assert.IsInstanceOfType(all, typeof(BigXmlNodeInternal));
            Assert.AreEqual<string>("xs:all", all.Name);
            Assert.AreEqual<string>(XsNamespaceUri, all.NamespaceURI);
            Assert.AreEqual(maxOccurs.ToString(), all.Attributes[":maxOccurs:"].Value);
            Assert.AreEqual(minOccurs.ToString(), all.Attributes[":minOccurs:"].Value);
            Assert.AreEqual(id, all.Attributes[":id:"].Value);
        }

        [TestMethod]
        public void XsdElementAnnotation() {
            const string id = "1";

            var annotation = XsdFactory.CreateElementAnnotation(model, id, null, null);
            Assert.IsNotNull(annotation);
            Assert.AreEqual("xs:annotation", annotation.Name);
            Assert.AreEqual(id, annotation.Attributes[":id:"].Value);
        }

        [TestMethod]
        public void XsdElementAny() {
            const string id = "1";
            const string maxOccurs = "1";
            const string minOccurs = "1";
            const string @namespace = "##any";
            const ProcessContents processContents = ProcessContents.Strict;

            var any = XsdFactory.CreateElementAny(model, id, maxOccurs, minOccurs, @namespace, processContents, null, null);
            Assert.IsNotNull(any);
            Assert.AreEqual("xs:any", any.Name);
            Assert.AreEqual(id, any.Attributes[":id:"].Value);
            Assert.AreEqual(maxOccurs.ToString(), any.Attributes[":maxOccurs:"].Value);
            Assert.AreEqual(minOccurs.ToString(), any.Attributes[":minOccurs:"].Value);
            Assert.AreEqual(@namespace, any.Attributes[":namespace:"].Value);
            Assert.AreEqual(processContents.ToString().ToLower(), any.Attributes[":processContents:"].Value);
        }

        [TestMethod]
        public void XsdAnyAttribute() {
            const string id = "1";
            const string @namespace = "##any";
            const ProcessContents processContents = ProcessContents.Strict;

            var anyAttribute = XsdFactory.CreateElementAnyAttribute(model, id, @namespace, processContents, null, null);
            Assert.IsNotNull(anyAttribute);
            Assert.AreEqual("xs:anyAttribute", anyAttribute.Name);
            Assert.AreEqual(id, anyAttribute.Attributes[":id:"].Value);
            Assert.AreEqual(@namespace, anyAttribute.Attributes[":namespace:"].Value);
            Assert.AreEqual(processContents.ToString().ToLower(), anyAttribute.Attributes[":processContents:"].Value);
        }

        [TestMethod]
        public void XsdAppInfo() {
            var appInfo = XsdFactory.CreateElementAppInfo(model, null, null);
            Assert.IsNotNull(appInfo);
            Assert.AreEqual("xs:appInfo", appInfo.Name);
        }

        [TestMethod]
        public void XsdAttribute() {
            const string @default = "test";
            const Form form = Form.Unqualified;
            const string id = "1";
            const string name = "attribute";
            const string type = "xs:string";
            const Use use = Use.Required;

            var attribute = XsdFactory.CreateElementAttribute(model, @default, null, form, id, name, null, type, use, null, null);
            Assert.IsNotNull(attribute);
            Assert.AreEqual("xs:attribute", attribute.Name);
            Assert.AreEqual(@default, attribute.Attributes[":default:"].Value);
            Assert.AreEqual(form.ToString().ToLower(), attribute.Attributes[":form:"].Value);
            Assert.AreEqual(id, attribute.Attributes[":id:"].Value);
            Assert.AreEqual(name, attribute.Attributes[":name:"].Value);
            Assert.AreEqual(type, attribute.Attributes[":type:"].Value);
            Assert.AreEqual(use.ToString().ToLower(), attribute.Attributes[":use:"].Value);
        }

        [TestMethod]
        public void XsdAttributeGroup() {
            const string id = "1";
            const string name = "attGroup";

            var attributeGroup = XsdFactory.CreateElementAttributeGroup(model, id, name, null, null, null);
            Assert.IsNotNull(attributeGroup);
            Assert.AreEqual("xs:attributeGroup", attributeGroup.Name);
            Assert.AreEqual(id, attributeGroup.Attributes[":id:"].Value);
            Assert.AreEqual(name, attributeGroup.Attributes[":name:"].Value);
        }

        [TestMethod]
        public void XsdChoice() {
            const string id = "1";
            const string maxOccurs = "1";
            const string minOccurs = "1";

            var choice = XsdFactory.CreateElementChoice(model, id, maxOccurs, minOccurs, null, null);
            Assert.IsNotNull(choice);
            Assert.AreEqual("xs:choice", choice.Name);
            Assert.AreEqual(id, choice.Attributes[":id:"].Value);
            Assert.AreEqual(maxOccurs.ToString(), choice.Attributes[":maxOccurs:"].Value);
            Assert.AreEqual(minOccurs.ToString(), choice.Attributes[":minOccurs:"].Value);
        }

        [TestMethod]
        public void XsdComplexContent() {
            const string id = "1";
            const bool mixed = true;

            var complexContent = XsdFactory.CreateElementComplexContent(model, id, mixed, null, null);
            Assert.IsNotNull(complexContent);
            Assert.AreEqual("xs:complexContent", complexContent.Name);
            Assert.AreEqual(id, complexContent.Attributes[":id:"].Value);
            Assert.AreEqual("true", complexContent.Attributes[":mixed:"].Value);
        }

        [TestMethod]
        public void XsdComplexType() {
            const string id = "1";
            const string name = "testType";
            const bool @abstract = false;
            const bool mixed = true;
            const string block = "restriction";
            const string final = "restriction";

            var complexType = XsdFactory.CreateElementComplexType(model, id, name, @abstract, mixed, block, final, null, null);
            Assert.IsNotNull(complexType);
            Assert.AreEqual("xs:complexType", complexType.Name);
            Assert.AreEqual(id, complexType.Attributes[":id:"].Value);
            Assert.AreEqual(name, complexType.Attributes[":name:"].Value);
            Assert.AreEqual("false", complexType.Attributes[":abstract:"].Value);
            Assert.AreEqual("true", complexType.Attributes[":mixed:"].Value);
            Assert.AreEqual(block, complexType.Attributes[":block:"].Value);
            Assert.AreEqual(final, complexType.Attributes[":final:"].Value);
        }

        [TestMethod]
        public void XsdDocumentation() {
            const string source = "source";
            const string lang = "en";

            var documentation = XsdFactory.CreateElementDocumentation(model, source, lang, null);
            Assert.IsNotNull(documentation);
            Assert.AreEqual("xs:documentation", documentation.Name);
            Assert.AreEqual(source, documentation.Attributes[":source:"].Value);
            Assert.AreEqual(lang, documentation.Attributes["xml:lang:"].Value);
        }

        [TestMethod]
        public void XsdElement() {
            const string id = "1";
            const string name = "element";
            const string type = "xsd:string";
            const Form form = Form.Unqualified;
            const string maxOccurs = "2";
            const string minOccurs = "1";
            const bool nillable = true;
            const bool @abstract = false;
            const string block = "extension";
            const string final = "#all";

            var element = XsdFactory.CreateElementElement(model, id, name, null, type, null, null,
                null, form, maxOccurs, minOccurs, nillable, @abstract, block, final, null, null);
            Assert.IsNotNull(element);
            Assert.AreEqual("xs:element", element.Name);
            Assert.AreEqual(id, element.Attributes[":id:"].Value);
            Assert.AreEqual(name, element.Attributes[":name:"].Value);
            Assert.AreEqual(type, element.Attributes[":type:"].Value);
            Assert.AreEqual(form.ToString().ToLower(), element.Attributes[":form:"].Value);
            Assert.AreEqual(maxOccurs, element.Attributes[":maxOccurs:"].Value);
            Assert.AreEqual(minOccurs, element.Attributes[":minOccurs:"].Value);
            Assert.AreEqual("true", element.Attributes[":nillable:"].Value);
            Assert.AreEqual("false", element.Attributes[":abstract:"].Value);
            Assert.AreEqual(block, element.Attributes[":block:"].Value);
            Assert.AreEqual(final, element.Attributes[":final:"].Value);
        }

        [TestMethod]
        public void XsdExtension() {
            const string id = "1";
            const string @base = "xs:string";

            var extension = XsdFactory.CreateElementExtension(model, id, @base, null, null);
            Assert.IsNotNull(extension);
            Assert.AreEqual("xs:extension", extension.Name);
            Assert.AreEqual(id, extension.Attributes[":id:"].Value);
            Assert.AreEqual(@base, extension.Attributes[":base:"].Value);
        }

        [TestMethod]
        public void XsdField() {
            const string id = "1";
            const string xpath = "//item";

            var field = XsdFactory.CreateElementField(model, id, xpath, null, null);
            Assert.IsNotNull(field);
            Assert.AreEqual("xs:field", field.Name);
            Assert.AreEqual(id, field.Attributes[":id:"].Value);
            Assert.AreEqual(xpath, field.Attributes[":xpath:"].Value);
        }

        [TestMethod]
        public void XsdGroup() {
            const string id = "1";
            const string name = "group";
            const string maxOccurs = "unbounded";
            const string minOccurs = "1";

            var group = XsdFactory.CreateElementGroup(model, id, name, null, maxOccurs, minOccurs, null, null);
            Assert.IsNotNull(group);
            Assert.AreEqual("xs:group", group.Name);
            Assert.AreEqual(id, group.Attributes[":id:"].Value);
            Assert.AreEqual(name, group.Attributes[":name:"].Value);
            Assert.AreEqual(maxOccurs, group.Attributes[":maxOccurs:"].Value);
            Assert.AreEqual(minOccurs, group.Attributes[":minOccurs:"].Value);
        }

        [TestMethod]
        public void XsdImport() {
            const string id = "1";
            const string @namespace = "http://xmlstudio.cz";
            const string schemaLocation = "location";

            var import = XsdFactory.CreateElementImport(model, id, @namespace, schemaLocation, null, null);
            Assert.IsNotNull(import);
            Assert.AreEqual("xs:import", import.Name);
            Assert.AreEqual(id, import.Attributes[":id:"].Value);
            Assert.AreEqual(@namespace, import.Attributes[":namespace:"].Value);
            Assert.AreEqual(schemaLocation, import.Attributes[":schemaLocation:"].Value);
        }

        [TestMethod]
        public void XsdInclude() {
            const string id = "1";
            const string schemaLocation = "test.xsd";

            var include = XsdFactory.CreateElementInclude(model, id, schemaLocation, null, null);
            Assert.IsNotNull(include);
            Assert.AreEqual("xs:include", include.Name);
            Assert.AreEqual(id, include.Attributes[":id:"].Value);
            Assert.AreEqual(schemaLocation, include.Attributes[":schemaLocation:"].Value);
        }

        [TestMethod]
        public void XsdKey() {
            const string id = "1";
            const string name = "name";

            var key = XsdFactory.CreateElementKey(model, id, name, null, null);
            Assert.IsNotNull(key);
            Assert.AreEqual("xs:key", key.Name);
            Assert.AreEqual(id, key.Attributes[":id:"].Value);
            Assert.AreEqual(name, key.Attributes[":name:"].Value);
        }

        [TestMethod]
        public void XsdKeyRef() {
            const string id = "1";
            const string name = "keyRef";
            const string refer = "refer";

            var keyRef = XsdFactory.CreateElementKeyRef(model, id, name, refer, null, null);
            Assert.IsNotNull(keyRef);
            Assert.AreEqual("xs:keyRef", keyRef.Name);
            Assert.AreEqual(id, keyRef.Attributes[":id:"].Value);
            Assert.AreEqual(name, keyRef.Attributes[":name:"].Value);
            Assert.AreEqual(refer, keyRef.Attributes[":refer:"].Value);
        }

        [TestMethod]
        public void XsdList() {
            const string id = "1";
            const string itemType = "type";

            var list = XsdFactory.CreateElementList(model, id, itemType, null, null);
            Assert.IsNotNull(list);
            Assert.AreEqual("xs:list", list.Name);
            Assert.AreEqual(id, list.Attributes[":id:"].Value);
            Assert.AreEqual(itemType, list.Attributes[":itemType:"].Value);
        }

        [TestMethod]
        public void XsdNotation() {
            const string id = "1";
            const string name = "notation";
            const string @public = "uri";
            const string system = "anotherUri";

            var notation = XsdFactory.CreateElementNotation(model, id, name, @public, system, null, null);
            Assert.IsNotNull(notation);
            Assert.AreEqual("xs:notation", notation.Name);
            Assert.AreEqual(id, notation.Attributes[":id:"].Value);
            Assert.AreEqual(name, notation.Attributes[":name:"].Value);
            Assert.AreEqual(@public, notation.Attributes[":public:"].Value);
            Assert.AreEqual(system, notation.Attributes[":system:"].Value);
        }

        [TestMethod]
        public void XsdRedefine() {
            const string id = "1";
            const string schemaLocation = "location";

            var redefine = XsdFactory.CreateElementRedefine(model, id, schemaLocation, null, null);
            Assert.IsNotNull(redefine);
            Assert.AreEqual("xs:redefine", redefine.Name);
            Assert.AreEqual(id, redefine.Attributes[":id:"].Value);
            Assert.AreEqual(schemaLocation, redefine.Attributes[":schemaLocation:"].Value);
        }

        [TestMethod]
        public void XsdRestriction() {
            const string id = "1";
            const string @base = "xs:string";

            var restriction = XsdFactory.CreateElementRestriction(model, id, @base, null, null);
            Assert.IsNotNull(restriction);
            Assert.AreEqual("xs:restriction", restriction.Name);
            Assert.AreEqual(id, restriction.Attributes[":id:"].Value);
            Assert.AreEqual(@base, restriction.Attributes[":base:"].Value);
        }

        [TestMethod]
        public void XsdSchema() {
            const string id = "1";
            const Form attributeFormDefault = Form.Unqualified;
            const Form elementFormDefault = Form.Qualified;
            const string blockDefault = "extension";
            const string finalDefault = "extension";
            const string targetNamespace = "some namespace";
            const string version = "1.0";
            const string xmlns = "some namespace";

            var schema = XsdFactory.CreateElementSchema(model, id, attributeFormDefault, elementFormDefault,
                blockDefault, finalDefault, targetNamespace, version, xmlns, null, null);
            Assert.IsNotNull(schema);
            Assert.AreEqual("xs:schema", schema.Name);
            Assert.AreEqual(attributeFormDefault.ToString().ToLower(), schema.Attributes[":attributeFormDefault:"].Value);
            Assert.AreEqual(elementFormDefault.ToString().ToLower(), schema.Attributes[":elementFormDefault:"].Value);
            Assert.AreEqual(blockDefault, schema.Attributes[":blockDefault:"].Value);
            Assert.AreEqual(finalDefault, schema.Attributes[":finalDefault:"].Value);
            Assert.AreEqual(targetNamespace, schema.Attributes[":targetNamespace:"].Value);
            Assert.AreEqual(version, schema.Attributes[":version:"].Value);
            Assert.AreEqual(xmlns, schema.NamespaceURI);
        }

        [TestMethod]
        public void XsdSelector() {
            const string id = "1";
            const string xpath = "//element";

            var selector = XsdFactory.CreateElementSelector(model, id, xpath, null, null);
            Assert.IsNotNull(selector);
            Assert.AreEqual("xs:selector", selector.Name);
            Assert.AreEqual(id, selector.Attributes[":id:"].Value);
            Assert.AreEqual(xpath, selector.Attributes[":xpath:"].Value);
        }

        [TestMethod]
        public void XsdSequence() {
            const string id = "1";
            const string maxOccurs = "10";
            const string minOccurs = "1";

            var sequence = XsdFactory.CreateElementSequence(model, id, maxOccurs, minOccurs, null, null);
            Assert.IsNotNull(sequence);
            Assert.AreEqual("xs:sequence", sequence.Name);
            Assert.AreEqual(maxOccurs, sequence.Attributes[":maxOccurs:"].Value);
            Assert.AreEqual(minOccurs, sequence.Attributes[":minOccurs:"].Value);
        }

        [TestMethod]
        public void XsdSimpleContent() {
            const string id = "1";

            var simpleContent = XsdFactory.CreateElementSimpleContent(model, id, null, null);
            Assert.IsNotNull(simpleContent);
            Assert.AreEqual("xs:simpleContent", simpleContent.Name);
            Assert.AreEqual(id, simpleContent.Attributes[":id:"].Value);
        }

        [TestMethod]
        public void XsdSimpleType() {
            const string id = "1";
            const string name = "testType";

            var simpleType = XsdFactory.CreateElementSimpleType(model, id, name, null, null);
            Assert.IsNotNull(simpleType);
            Assert.AreEqual("xs:simpleType", simpleType.Name);
            Assert.AreEqual(id, simpleType.Attributes[":id:"].Value);
            Assert.AreEqual(name, simpleType.Attributes[":name:"].Value);
        }

        [TestMethod]
        public void XsdUnion() {
            const string id = "1";
            const string memberTypes = "sizebyno sizebystring";

            var union = XsdFactory.CreateElementUnion(model, id, memberTypes, null, null);
            Assert.IsNotNull(union);
            Assert.AreEqual("xs:union", union.Name);
            Assert.AreEqual(id, union.Attributes[":id:"].Value);
            Assert.AreEqual(memberTypes, union.Attributes[":memberTypes:"].Value);
        }

        [TestMethod]
        public void XsdUnique() {
            const string id = "1";
            const string name = "unique";

            var unique = XsdFactory.CreateElementUnique(model, id, name, null, null);
            Assert.IsNotNull(unique);
            Assert.AreEqual("xs:unique", unique.Name);
            Assert.AreEqual(id, unique.Attributes[":id:"].Value);
            Assert.AreEqual(name, unique.Attributes[":name:"].Value);
        }

        [TestMethod]
        public void XsdFacetEnumeration() {
            const string value = "XmlStudio";
            var enumeration = XsdFactory.CreateFacet(model, XsdFacet.enumeration, value);
            Assert.IsNotNull(enumeration);
            Assert.AreEqual("xs:enumeration", enumeration.Name);
            Assert.AreEqual(value, enumeration.Attributes[":value:"].Value);
        }

        [TestMethod]
        public void XsdFacetFractionDigits() {
            const string value = "XmlStudio";
            var fractionDigits = XsdFactory.CreateFacet(model, XsdFacet.fractionDigits, value);
            Assert.IsNotNull(fractionDigits);
            Assert.AreEqual("xs:fractionDigits", fractionDigits.Name);
            Assert.AreEqual(value, fractionDigits.Attributes[":value:"].Value);
        }

        [TestMethod]
        public void XsdFacetLength() {
            const string value = "XmlStudio";
            var length = XsdFactory.CreateFacet(model, XsdFacet.length, value);
            Assert.IsNotNull(length);
            Assert.AreEqual("xs:length", length.Name);
            Assert.AreEqual(value, length.Attributes[":value:"].Value);
        }

        [TestMethod]
        public void XsdFacetMaxExclusive() {
            const string value = "XmlStudio";
            var maxExclusive = XsdFactory.CreateFacet(model, XsdFacet.maxExclusive, value);
            Assert.IsNotNull(maxExclusive);
            Assert.AreEqual("xs:maxExclusive", maxExclusive.Name);
            Assert.AreEqual(value, maxExclusive.Attributes[":value:"].Value);
        }

        [TestMethod]
        public void XsdFacetMaxInclusive() {
            const string value = "XmlStudio";
            var maxInclusive = XsdFactory.CreateFacet(model, XsdFacet.maxInclusive, value);
            Assert.IsNotNull(maxInclusive);
            Assert.AreEqual("xs:maxInclusive", maxInclusive.Name);
            Assert.AreEqual(value, maxInclusive.Attributes[":value:"].Value);
        }

        [TestMethod]
        public void XsdFacetMaxLength() {
            const string value = "XmlStudio";
            var maxLength = XsdFactory.CreateFacet(model, XsdFacet.maxLength, value);
            Assert.IsNotNull(maxLength);
            Assert.AreEqual("xs:maxLength", maxLength.Name);
            Assert.AreEqual(value, maxLength.Attributes[":value:"].Value);
        }

        [TestMethod]
        public void XsdFacetMinExclusive() {
            const string value = "XmlStudio";
            var minExclusive = XsdFactory.CreateFacet(model, XsdFacet.minExclusive, value);
            Assert.IsNotNull(minExclusive);
            Assert.AreEqual("xs:minExclusive", minExclusive.Name);
            Assert.AreEqual(value, minExclusive.Attributes[":value:"].Value);
        }

        [TestMethod]
        public void XsdFacetMinInclusive() {
            const string value = "XmlStudio";
            var minInclusive = XsdFactory.CreateFacet(model, XsdFacet.minInclusive, value);
            Assert.IsNotNull(minInclusive);
            Assert.AreEqual("xs:minInclusive", minInclusive.Name);
            Assert.AreEqual(value, minInclusive.Attributes[":value:"].Value);
        }

        [TestMethod]
        public void XsdFacetMinLength() {
            const string value = "XmlStudio";
            var minLength = XsdFactory.CreateFacet(model, XsdFacet.minLength, value);
            Assert.IsNotNull(minLength);
            Assert.AreEqual("xs:minLength", minLength.Name);
            Assert.AreEqual(value, minLength.Attributes[":value:"].Value);
        }

        [TestMethod]
        public void XsdFacetPattern() {
            const string value = "XmlStudio";
            var pattern = XsdFactory.CreateFacet(model, XsdFacet.pattern, value);
            Assert.IsNotNull(pattern);
            Assert.AreEqual("xs:pattern", pattern.Name);
            Assert.AreEqual(value, pattern.Attributes[":value:"].Value);
        }

        [TestMethod]
        public void XsdFacetTotalDigits() {
            const string value = "XmlStudio";
            var totalDigits = XsdFactory.CreateFacet(model, XsdFacet.totalDigits, value);
            Assert.IsNotNull(totalDigits);
            Assert.AreEqual("xs:totalDigits", totalDigits.Name);
            Assert.AreEqual(value, totalDigits.Attributes[":value:"].Value);
        }

        [TestMethod]
        public void XsdFacetWhiteSpace() {
            const string value = "XmlStudio";
            var whiteSpace = XsdFactory.CreateFacet(model, XsdFacet.whiteSpace, value);
            Assert.IsNotNull(whiteSpace);
            Assert.AreEqual("xs:whiteSpace", whiteSpace.Name);
            Assert.AreEqual(value, whiteSpace.Attributes[":value:"].Value);
        }

        [TestMethod]
        public void XsdBuiltInTypesTest() {
            var types = XsdDataTypeHelper.ListBuiltInXsdTypesTuple();
            Assert.IsNotNull(types);
            Assert.AreEqual<int>(43, types.Count());
        }
    }
}
